import xlwt
from report import HmTable, HmDocx
from ODBC_report import NotebookDocx, logger, printf, CR 
from index_DTR import ExecusStatistics
from natsort import natsorted
from colorama import Fore, init
init(autoreset=True)
import traceback
import os
import re
import copy
import json

from hm.common import have_word
from hm.hos import OSname
from report import XLS
        

class RequirementVerificationTbl(HmTable):
    def __init__(self, t, parent):
        '''
        '''
        self.name = "Requirement Verification"
        if t:
            super().__init__(t, parent)
            # assert self.is_me, f'不是{self.name}表格'
            self.is_me = self._is_me()
            if self.is_me:
                logger.info(f"********** 初始化{self.name}表格 **********")
        else:
            self.parent = parent
            self.table = None
        self.requirements = self.get_requirements()

    def get_requirements(self):
        '''
        return: {'requirement xxx': {'TestCaseNO':[], 'chapter':[], 'description':'', 'fail_info':[],
                                 'result':'Passed', 'retested_pass':False
                                } 
                }
        '''
        result = {}
        for e in self.parent.executions:
            retested_r = []  # 重测是文件级别的，此执行文件下的所有表格都是重测
            for t in e.execution_tables:
                for info in t.steps_info: # 当前步骤验证的需求
                    for r in info["requirements"]:
                        # if r not in result or e.is_retested:  # 20240606 retest报告中，如果不同step出现同样的需求，会导致重复重置result
                        if r not in result or (e.is_retested and not retested_r): # 重测pass的步骤，重置fail_info
                            result[r] = {'TestCaseNO':[], 'chapter':[], 'description':'', 'fail_info':[],
                                         'result':'Passed', 'retested_pass':False}    
                        if t.TestCaseNO not in result[r]['TestCaseNO']:   
                            result[r]['TestCaseNO'].append(t.TestCaseNO)
                        # if e.chapter not in result[r]['chapter']:
                            result[r]['chapter'].append(e.chapter)
                        if r in t.Requirements:
                            result[r]['description'] = t.Requirements[r]
                        if not info['is_pass'] and not result[r]['retested_pass']: # 重测pass的TestCase不再统计fail信息
                            result[r]['fail_info'].append({'TestCaseNO':t.TestCaseNO, 'case_name':e.case_name,
                                                        "SystemID":t.SystemID, "step_info":info})
                            result[r]['result'] = info['Status'] 
                            
                        if e.is_retested and r not in retested_r:
                            retested_r.append(r)
            # 重测pass的用例，设置'retested_pass'为True
            for r in retested_r:
                if not result[r]['fail_info']:
                    result[r]['retested_pass'] = True
        # logger.info(f"总需求列表{json.dumps(result, indent=8)}") # todo 这里会报错 _Row is not JSON serializable
        return result

    def check(self):
        '''
            1. 遍历表格每一行需求
            2. 如果该需求在：self.requirements中，
                1）判断测试结果是否正确
                2）判断是否包含全部的TestCaseNo
            3. 如果该需求不在requirements中，报错
            4. 自动生成此表格
        '''
        if not self.table:
            yield f"没有找到{self.name}表格"
        else:
            requirements = copy.deepcopy(self.requirements)
            for row in self.rows[1:]:
                requirement = row.cells[0].text.strip()
                test_case = row.cells[-2].text.strip()
                result = row.cells[-1].text.strip()
                if requirement in requirements:
                    # 检查测试结果
                    fail_info = requirements[requirement]['fail_info']
                    correct_result = requirements[requirement]['result'].strip().strip(".")
                    if not have_word(correct_result, result):
                        err = f"需求{requirement}的结果“{result}”不正确，应为“{correct_result}”"
                        if fail_info:
                            err += f"，参见{fail_info[0]['case_name']} {fail_info[0]['SystemID']} step{fail_info[0]['step_info']['step_num']}"
                        yield CR.error(err)
                    # 检查test_case
                    TestCaseNOs = requirements[requirement]["TestCaseNO"]
                    for NO in TestCaseNOs:
                        if not have_word(NO, test_case):
                            yield CR.error(f'需求{requirement}未包含{NO}')
                    requirements.pop(requirement)
            # 检查未总结的需求
            for r in requirements:
                yield CR.error(f"需求{r}未总结")
            # for err in self.gen_tbl():
            #     yield err

    def gen_tbl(self):
        '''
            创建Requirement Verification表 +  Test Cases to Requirements表
        '''
        datas = []
        datas2 = {}
        for key, val in self.requirements.items():
            # 获取第一个表格数据
            test_case = ''
            for i, case in enumerate(val["TestCaseNO"]):
                if test_case:
                    test_case+='\n'
                test_case += case+"\n"+val["chapter"][i]
            datas.append([key, val['description'], test_case, val['result']])

            # 获取第二个表格数据
            chapter = val["chapter"]
            for c in chapter:
                if c not in datas2:
                    datas2[c] = []
                if key not in datas2[c]:
                    datas2[c].append(key)

        title = ["Requirements NO.", "Description", "Test Case", "Result"]
        datas = natsorted(datas, key=lambda k:k[0])
        xls = XLS()
        xls.write_table(f'{self.name}', title, datas, width=[(1,14000), (2,10000)])
        yield f"{Fore.GREEN}创建{self.name}表"
        
        title = ["Plan #", "Test Case", "Requirements Tested"]
        datas3 = []
        for e in self.parent.executions: # 为了按章节排序
            requirements = ''
            if e.chapter in datas2:
                requirements = ', '.join(natsorted(datas2[e.chapter]))
            line = ['', e.chapter, requirements]
            if line not in datas3:
                datas3.append(line)
        xls.write_table('Test Cases to Requirements', title, datas3, width=[(0,3000),(1,10000),(2,12000)])
        yield f"{Fore.GREEN}创建Test Cases to Requirements表"
        
    # def gen_tbl_by_test_plan(self, test_plan_path):
    #     '''
    #         通过test plan自动生成此表格
    #     '''
    #     self.test_plan = HmDocx(test_plan_path)
    #     for t in self.test_plan.tables:
    #         cells = t.rows[0].cells
    #         if have_word("Input document", cells[0].text) and have_word("Requirement.NO", cells[1].text):
    #             print("找到table", [i.text for i in cells])
    #             # workbook = xlwt.Workbook()
    #             workbook = self.parent.workbook
    #             worksheet = workbook.add_sheet('requirement_status')
    #             title = ["Requirements NO.", "Description", "Test Case", "Result"]
    #             for i, string in enumerate(title):
    #                 worksheet.write(0, i, string)
    #             for i, row in enumerate(t.rows[1:]):
    #                 cells = row.cells
    #                 req = cells[1].text.strip()
    #                 worksheet.write(i+1, 0, cells[1].text) # Requirements NO.
    #                 worksheet.write(i+1, 1, cells[2].text) # Description
    #                 worksheet.write(i+1, 2, cells[3].text+"\n"+cells[4].text) # Test Case
    #                 if req in self.requirements:
    #                     result = self.requirements[req]['result']
    #                     worksheet.write(i+1, 3, result)

    def _is_me(self):
        cells = self.rows[0].cells
        if have_word("Requirements NO", cells[0].text) and \
            have_word('Description', cells[1].text):
            return True
        return False


class SumTestedItemmTbl(HmTable):
    def __init__(self, t, parent):
        '''
        
        '''
        self.name = "Summary of Tested Items"
        if t:
            super().__init__(t, parent)
            # assert self.is_me, f'不是{self.name}表格'
            self.is_me = self._is_me()
            if self.is_me:
                logger.info("********** 初始化{self.name}表格 **********")
        else:
            self.parent = parent
            self.table = None
    
    def check(self):
        yield f'还在开发{self.name}表格的检查方法...'
    
    def gen_tbl_datas(self):
        datas = []
        datas2 = []
        datas3 = []
        # todo dates和datas2需要特殊处理 '重测的报告'
        for e in self.parent.executions:
            test_result = "Passed"
            chapter = e.chapter
            if e.is_retested:
                chapter += '-' + e.case_name
            # 获取表格1数据
            for t in e.execution_tables:
                # print(t._max_time, t._min_time) 
                # 不知道为什么两个是这样的 2024-03-26 00:00:00 和26-Mar-2024
                # if t._max_time != t._min_time:  
                if t.StartDate != t.EndDate:
                    date = t.StartDate +" to "+ t.EndDate
                else:
                    date = t.StartDate
                datas.append([
                    chapter, t.SystemID, date, t.SoftwareVersion, t.Tester, t.TotalSteps, t.StepsPassed, t.StepsFailed, "N/A"
                ])
                # 用例失败
                if not t.is_pass:
                    test_result = "Failed"
            # 获取表格2数据
            datas2.append([e.case_name, test_result, "N/A"])
            # 获取表格3数据
            datas3.append(['', e.chapter, OSname(e.filename), ''])
        datas3.append(['', 'N/A', 'TestSummaryReport-ODBC-XXXX\nDefect Tracking Record_XXXX\nQST-ODBC-M2-XXXX-R0004 XXXX', ''])
        return datas, datas2, datas3
    
    def gen_tbl(self):
        datas, datas2, datas3 = self.gen_tbl_datas()
        xls = XLS()
        # 写入表格1
        title = ["Test Case ID", "System ID", "Test Dates", "Software Version/ Main Control Version", "Tester",
                 "Total # Test Steps", "Total # Steps Pass from Steps Performed", 
                 "Total # Steps Fail from Steps Performed", "Notes"]
        worksheet = xls.write_table('Summry_tested_item', title, [], 
                                    width=[(0,6000),(2,6000),(5,4000),(6,4000),(7,4000),(8,4000)])
        style = xls.style
        start, start4 = 0, 0
        for i,data in enumerate(datas):
            for j,value in enumerate(data):
                if j==0:
                    if i+1<len(datas) and value==datas[i+1][j]: # 当前单元格的值与下一行同列的单元格的值相同
                        if i==0 or value!=datas[i-1][j]: # 并且与上一行同列的单元格的值不同，则不写入内容（合并单元格）
                            start = i
                    else:
                        worksheet.write_merge(start+1, i+1, j, j, value, style)
                        start = i+1
                # todo 写的太丑了
                elif j==4:
                    if i+1<len(datas) and value==datas[i+1][j] and datas[i][0]==datas[i+1][0]:
                        if i==0 or value!=datas[i-1][j]:
                            start4 = i
                    else:
                        worksheet.write_merge(start4+1, i+1, j, j, value, style)
                        start4=i+1
                else:
                    worksheet.write(i+1, j, value, style)
        yield f"{Fore.GREEN}创建{self.name}表"
        
        
        # 写入表格2
        title = ["Plan #", "Status", "Remarks"]
        xls.write_table('Test case statistics', title, datas2, width=[(0,10000)])
        yield f"{Fore.GREEN}创建Test case statistics表"
        
        # 写入表格3
        title = ["Proc. #", "Test Case ID", "Supporting Data/ File Name", "File Location"]
        xls.write_table('Summary of Supporting Data', title, datas3, width=[(1,10000), (2,10000)])
        yield f"{Fore.GREEN}创建Summary of Supporting Data表"
    
    
    def _is_me(self):
        cells = self.rows[0].cells
        if have_word("Test Case ID", cells[0].text) and self.locate_cell('Tester', re.I, 0):
            return True
        return False


class FinalReport(NotebookDocx, ExecusStatistics):
    def __init__(self, path, *args, **kwargs):
        '''
            创建报告统计表
            检查总报告
        '''
        if not "only_setup" in kwargs:
            NotebookDocx.__init__(self, path)
            if self.is_me and args:
                self.setup(*args)
    
    def _is_me(self):
        self.init_tbl()
        if self.req_verification_Tbl:
            return True
        else:
            return False      
    
    def setup(self, *args):
        ExecusStatistics.__init__(self, args[0])
        
    def find_tbl(self, t, t_class):
        try:
            table = t_class(t, self)
            return table
        except:
            # traceback.print_exc()
            return

    def init_tbl(self):
        self.req_verification_Tbl = None
        self.sum_tested_items_tbl =  None
        for t in self.tables:
            if self.req_verification_Tbl is None:
                self.req_verification_Tbl = self.find_tbl(t, RequirementVerificationTbl)
            if self.sum_tested_items_tbl is None:
                self.sum_tested_items_tbl = self.find_tbl(t, SumTestedItemmTbl)
    
    def gen_DTRs_tbl(self):
        DTR_data_original, DTR_data_table, case_edit_data = self.get_eDTRs(self.executions)
        title = ["DTR #", "Description", "Instrument NO/Software version", "step #"]
        xls = XLS()
        xls.write_table('Summary of DTRs', title, DTR_data_table, width=[(1,18000), (2,10000), (3, 8000)])
        title = ["#", "Changed chapters", "change step", "Requirements", "Reason for change", "Tester", "time"]
        for i in range(len(case_edit_data)):
            case_edit_data[i][4] = case_edit_data[i][4]['ActualResult']
        xls.write_table('TEST CASE EDIT', title, case_edit_data, width=[(0,1000), (3,8000), (4, 15000)])
    
    def gen_tbls(self):
        req_verification_Tbl = RequirementVerificationTbl(None, self)
        sum_tested_items_tbl = SumTestedItemmTbl(None, self)
        # 创建DTR表
        self.gen_DTRs_tbl()
        yield f"    {Fore.GREEN}创建Summary of DTRs表"
        # 创建Requirement_Verification表 + Test Cases to Requirements表
        for err in req_verification_Tbl.gen_tbl():
            yield f"    {err}"   
        # 创建Summary of Tested Items表
        for err in sum_tested_items_tbl.gen_tbl():
            yield f"    {err}"  
        # 保存创建的表格
        save_path = os.path.join(self.executions[0].notebook_dir, "finnal_report_output.xls")
        xls = XLS()
        xls.save(save_path)
        yield f"{Fore.GREEN}表格文件已保存至{save_path}"
    
    
    @classmethod
    def create_me(cls, executions):
        return False
        
    @classmethod
    def create_tables(cls, executions):
        final = FinalReport(path=None, only_setup=True)
        final.setup(executions)
        for err in final.gen_tbls():
            printf(f"    {err}")
        return True
    
    def check(self):
        yield f"\n\n{Fore.LIGHTGREEN_EX}检查文件 {self.filename}"
        # 检查Requirement_Verification表
        yield f"    {Fore.YELLOW}检查{self.req_verification_Tbl.name}表格"
        for err in self.req_verification_Tbl.check():
            yield f"        {err}"
        # 检查Summary of Tested Items表
        yield f"    {Fore.YELLOW}检查{self.sum_tested_items_tbl.name}表格"
        for err in self.sum_tested_items_tbl.check():
            yield f"        {err}"


if __name__ == "__main__":
    # path = r"E:\vitros450\SAHA\SAHA Test Notebook\QST-ODBC-M2-SAHA-R0004 LVCC Sample Handler(SAHA) Subsystem Test Report.docx"
    import sys
    path = sys.argv[1]
    f = FinalReport(path)
    for err in f.check():
        printf(err)


    
